/*
 * Copyright (c) 2010-2013 Ruben Chakhmakhchyan. All rights reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Eclipse Public License
 * Version 1.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://opensource.org/licenses/EPL-1.0 and read it before using this file.
 */

#pragma once

#include <stdlib.h>

#include "commontwain.h"
#include "dsm.h"
#include "message_listener.h"
#include "image_acquisition_model.h"
#include "image_site.h"
#include "list.h"


bool operator== ( const TW_FIX32& _fix1, const TW_FIX32& _fix2 );


class TwainModel : public ImageAcquisitionModel
{
private:

    typedef struct CapParams
    {
        TW_UINT16 id;
        TW_UINT16 type;

        bool get;
        bool set;
        bool getDefault;
        bool getCurrent;
        bool reset;

        bool querySupported; // indicates whether the MSG_QUERYSUPPORT is supported
        bool getSupported; // indicates whether the MSG_GET was successful
    } CapParams;

public:

    TwainModel( ImageSite* imageSite, MessageListener* messageListener );
    virtual ~TwainModel();

    // ImageAcquisitionModel implementation
    virtual int getModelTypeId() const { return 1; }
    virtual char* getModelTypeName() const { return ( char* ) m_modelTypeName; }
    virtual void setIdentity( char* productName );
    virtual bool getDevices();
    virtual ImagingDevice* getDevice( int index );
    virtual int getDeviceCount();

    virtual ResultCode scan();

    virtual PixelType getPixelType() const { return m_pixelType; }
    virtual void setPixelType( PixelType value ) { m_pixelType = value; }
    virtual uint_t getResolution() const { return m_resolution; }
    virtual void setResolution( uint_t value ) { m_resolution = value; }
    virtual PaperSource getPaperSource() const { return m_paperSource; }
    virtual void setPaperSource( PaperSource value );
    virtual bool getAutoBright() const { return m_autoBright; }
    virtual void setAutoBright( bool value ) { m_autoBright = value; }
    virtual int getContrast() const { return m_contrast; }
    virtual void setContrast( int value ) { m_contrast = value; }
    virtual double getPageWidth() const { return m_pageWidth; }
    virtual void setPageWidth( double value ) { if ( value > 0 ) m_pageWidth = value; }
    virtual double getPageHeight() const { return m_pageHeight; }
    virtual void setPageHeight( double value ) { if ( value > 0 ) m_pageHeight = value; }
    virtual void setPageSize( double width, double height ) { m_pageWidth = width; m_pageHeight = height; }

    virtual bool getIsPaperSourceFixed() const { return m_isPaperSourceFixed; }

    virtual bool getDuplex() const { return m_duplex; }
    virtual void setDuplex( bool value ) { m_duplex = m_isFeederSupported && value; }

    virtual int getOrientation() const { return m_orientation; }
    virtual void setOrientation( int value ) { m_orientation = value; }

    virtual bool getIsDeviceFeatureSupported( DeviceFeature deviceFeature ) const;
    virtual long initializeDevice();

    virtual bool getShowDeviceUI() const { return m_showDeviceUI; }
    virtual void setShowDeviceUI( bool value ) { m_showDeviceUI = value; }

    virtual void setParentWindow( void* handle ) { }

    virtual int getDeviceIndex() const { return m_deviceIndex; }
    virtual void setDeviceIndex( int index ) { m_deviceIndex = index; }

    virtual const ImagingDevice& getCurrentDevice() const { return m_devices[ m_deviceIndex ]; }

    virtual BaseCap* getCap( unsigned int cap );

    virtual bool connect();
    virtual void disconnect();
    virtual bool getIsConnected() const { return m_connected; }

    virtual void deviceChange( bool state );

public:

    bool getCap( int capId, BaseCap*& cap );

    TW_UINT16 dsmEntry( TW_UINT32 DG, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData ); // DSM_Entry function encapsulation.
    TW_UINT16 dsmEntry( pTW_IDENTITY pDest, TW_UINT32 DG, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData ); // DSM_Entry function encapsulation.


    // Retrieves the condition code from the DSM.
    // @param[in] _pdestID a pointer to the source to query, or 0 for the DSM
    // @param[out] _cc this will be set to the condition code
    // @return a valid TWRC_xxxx return code
    TW_UINT16 getTWCC( pTW_IDENTITY pdestID, TW_INT16& cc );

    virtual void fillIdentity( TW_IDENTITY& identity, TW_STR32 productName );

    void stop(); // Ends all the pending transfers, disables and unloads the data source and disables the DSM

    bool connectDSM(); // Tries to connect to the DSM. If successful moves the app to state 3.

    void disconnectDSM(); // Tries to disconnect from the DSM. If successful moves the app to state 2.

    void getDataSources();

    bool loadDS(); // Tries to load a Data Source. Loads the data source with the ID passed in. To open a Data Source the DSM must be in state 3 (Open). If successful moves the app to state 4

    void unloadDS(); // Unloads the currently loaded data source. If successful moves the app to state 3.

    // request the acquisition of data from the currently opened source. If successful moves app to state 5.
    virtual bool enableDS( TW_HANDLE hWnd, bool showUI, bool modalUI, bool UIOnly );
    virtual bool enableDS( TW_HANDLE hWnd );

    virtual void disableDS(); // Tries to disable the sources UI. If successful moves app to state 4.

    void initiateTransfer_Native(); // Starts the scanning process using native mode. Data will be transfered in native mode (DIB).

    TW_UINT16 setCapabilityValue( TW_UINT16 Cap, const int value, TW_UINT16 type );
    TW_UINT16 setCapabilityValue( TW_UINT16 Cap, const pTW_FIX32 pValue );
    TW_UINT16 setCapabilityValue( TW_UINT16 cap, const pTW_FRAME pValue );
    TW_UINT16 setCapabilityArray( TW_UINT16 cap, const int* pValues, int count, TW_UINT16 type );

    bool getCapabilityIntValue( TW_UINT16 capId, int& value );

    //TW_INT16 get_CAP( TW_CAPABILITY& cap, TW_UINT16 msg = MSG_GET );

    TW_INT16 queryCapSupport( TW_UINT16 capId, TW_UINT32& pattern );

    pTW_IDENTITY getAppIdentity(); // Returns a pointer to the applications identity structure.

    pTW_IDENTITY getDefaultDataSource(); // Gets a pointer to the default data source.

    void startScan();

    int m_dsmState;				// the current TWAIN state of the DSM (2-7)
    TW_UINT16 m_dsMessage;		// status to indicate if we are waiting for DS

    void EnableDS();

    void onTwainError( ResultCode errorCode );

    void initCap( TW_UINT16 id, CapParams& c );
    uint_t doThread();
    ResultCode doScan();
    void waitForEvent();

private:

    TW_IDENTITY m_identity;					// application's identity details
    pTW_IDENTITY m_pDataSource;				// currently loaded data source
    List<TW_IDENTITY> m_dataSources;
    TW_IDENTITY m_defaultDataSource;
    bool m_gotDataSources;

    //TW_IMAGEINFO m_imageInfo;					/**< Detailed image info retrieved from the DS */
    TW_UINT16 m_xferNum;						/**< Keep track of the number of images attempted to transfer - used when saving file to disk*/
    HWND m_hWnd2;
    TW_USERINTERFACE m_ui;                   // Coordinates UI between application and data source.

    MessageListener* m_messageListener; // message client

    // caps
    PaperSource m_paperSource;
    PixelType m_pixelType;
    uint_t m_resolution;
    PageSize m_pageSize;
    bool m_autoBright;
    int m_contrast;
    double m_pageWidth, m_pageHeight;
    bool m_isPaperSourceFixed;
    int m_orientation;
    bool m_duplex;

    List<ImagingDevice> m_devices;

    bool m_showDeviceUI;

    uint_t m_deviceIndex;
    ImagingDevice* m_currentDevice;

    static char m_modelTypeName[];

    ImageSite* m_imageSite;

    HWND m_parentWindow;

    bool m_connected, m_dsmConnected;

    bool m_isFlatbedSupported, m_isFeederSupported, m_isDuplexSupported;

    CapParams m_capPixelType, m_capBitDepth, m_capResolution, m_capUnits, 
        m_capOrientation, m_capRotation, m_capFrames, m_capSupportedSizes, m_capPhysicalWidth, m_capPhysicalHeight, 
        m_capFeederEnabled, m_capDuplex, m_capDuplexEnabled, m_capXferMech, m_capXferCount;

    DWORD m_threadId;
    HANDLE m_hThread;
    HANDLE m_hEvent;

    volatile int m_scanResult;

private:

    // CAPABILITIES
    /*
    TW_CAPABILITY m_CAP_XFERCOUNT;			// Number of images the application is willing to accept this session.
    TW_CAPABILITY m_ICAP_XFERMECH;			// Transfer mechanism - used to learn options and set-up for upcoming transfer.
    TW_CAPABILITY m_ICAP_IMAGEFILEFORMAT;	// File format saved when using File Xfer Mechanism.
    TW_CAPABILITY m_ICAP_COMPRESSION;		// Compression method used for upcoming transfer.
    TW_CAPABILITY m_ICAP_UNITS;				// Unit of measure (inches, centimeters, etc).
    TW_CAPABILITY m_ICAP_PIXELTYPE;			// The type of pixel data (B/W, gray, color, etc).
    TW_CAPABILITY m_ICAP_BITDEPTH;			// Pixel bit depth for Current value of ICAP_PIXELTYPE.
    TW_CAPABILITY m_ICAP_XRESOLUTION;		// Current/Available optical resolutions for x-axis.
    TW_CAPABILITY m_ICAP_YRESOLUTION;		// Current/Available optical resolutions for y-axis.
    TW_CAPABILITY m_ICAP_FRAMES;			// Size and location of frames on page.
    TW_CAPABILITY m_ICAP_ORIENTATION;		// Defines which edge of the paper is the top: Portrait or Landscape.
    TW_CAPABILITY m_ICAP_ROTATION;			// How the Source can/should rotate the scanned image data prior to transfer.
    TW_CAPABILITY m_CAP_FEEDERENABLED;		// Indicates if a Source has a document feeder available
    CAP_DEVICEONLINE
    */
};
